#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "compile.h"
#include "util/memory.h"

#include "checker/check.h"
#include "generators/c/generate.h"
#include "generators/llvm_ir/generate.h"
#include "optimizer/optimize.h"
#include "parser/parse.h"
#include "test.h"
#include "util/file.h"
#include "util/string.h"

#if 0
import std.io;
import std.lib;
import checker.check;
import generator.generate;
import optimizer.optimize;
import parser.parse;
import test;
import util.file;
import util.string;
#endif

int main(int argc, char** argv)
{
	// flags
	int flag_check_only = 0;
	int flag_optimize = 0;
	int flag_test = 0;

	int target_c = 0;
	int target_llvm = 0;

	struct StringList* sourceFiles = NULL;
	int i = 1;

	while(i < argc)
	{
		if(!strcmp(argv[i],"-c"))
			target_c = 1;

		else if(!strcmp(argv[i],"-llvm"))
			target_llvm = 1;

		else if(!strcmp(argv[i],"-co")
			|| !strcmp(argv[i],"--check-only"))
			flag_check_only = 1;

		else if(!strcmp(argv[i],"-o")
			|| !strcmp(argv[i],"--optimize"))
			flag_optimize = 1;

		else if(!strcmp(argv[i],"-t") || !strcmp(argv[i],"--test"))
			flag_test = 1;

		else if(stringStartsWith(argv[i],"-"))
		{
			printf("Unrecognized flag: %s\n",argv[i]);
			return 0;
		}

		else
			sourceFiles = stringListAppend(sourceFiles,argv[i]);

		i++;
	}

	if(flag_test)
		runTests();

	while(sourceFiles != NULL)
	{
		assert(sourceFiles->head != NULL);
		printf("Compiling source file: %s\n",sourceFiles->head);
		char* source = readfile(sourceFiles->head);

		assert(source != NULL);

		printf("Parsing source.\n");
		struct Module* ast = parse(source);

		assert(ast != NULL);

		printf("Checking for errors.\n");
		struct ErrorList* errors = check(ast);
		printErrors(errors);
		failOnFatalErrors(errors);

		if(!flag_check_only)
		{
			assert(ast != NULL);

			if(flag_optimize)
			{
				printf("Optimizing AST.\n");
				ast = optimize(ast);
			}

			char destfilename[256];

			assert(ast != NULL);

			if(target_c)
			{
				printf("Generating C.\n");
				char* c = c$generate(ast);
				printf("Writing C to %s.c.\n",sourceFiles->head);
				sprintf(destfilename,"%s.c",sourceFiles->head);
				writefile(destfilename,c);
			}

			if(target_llvm)
			{
				printf("Generating LLVM IR.\n");
				char* llvm_ir = llvm_ir$generate(ast);
				printf("Writing LLVM IR to %s.ll.\n",sourceFiles->head);
				sprintf(destfilename,"%s.ll",sourceFiles->head);
				writefile(destfilename,llvm_ir);
			}
		}

		struct StringList* tail = sourceFiles->tail;
		free(sourceFiles);
		sourceFiles = tail;
	}

	return 0;
}
